/**
  ******************************************************************************
  * @file Appli.c
  * @author  MCU Group Shanghai
  * @version  V3.0.0
  * @date  07/10/2009
  * @brief  Irda Send and Receive
  ******************************************************************************
  * @copy
  *
  * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
  * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
  * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
  * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
  * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
  * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
  *
  * <h2><center>&copy; COPYRIGHT 2009 STMicroelectronics</center></h2>
  */ 

/* Includes ------------------------------------------------------------------*/
#include "stm32f10x.h"
#include "appli.h"
#include "stm32f10x_tim.h"
#include "stm32f10x_exti.h"
#include "misc.h"

CAPTURE_STATUS capture_state;
volatile u32 num_capture_codes;
OUTPUT_STATUS output_state;

GLOBAL_STATUS global_state, global_state_backup;

#pragma location=0x20004000
__root __no_init uint16_t RmtCtrlCodeBuf[2048];
uint16_t *pRmtCtrlCodeBuf = RmtCtrlCodeBuf;

/* Private functions ---------------------------------------------------------*/
void Key_Configuration(void);

/**
  * @brief  configurate the tim2 to generate the Irda signal 
  * @param  None
  * @retval : None
  */

#define CR1_CEN_Set                 ((uint16_t)0x0001)
void Irda_Out_Compare_Configuration(void)
{
  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
  TIM_OCInitTypeDef  TIM_OCInitStructure;
  
  TIM_DeInit(TIM2);                        /* deinitiate tim2 */
  
  TIM_TimeBaseStructure.TIM_Period = 65535;       /* Time base configuration CK_INT=72M/(71+1)=1MHz */
  TIM_TimeBaseStructure.TIM_Prescaler = 0;
  TIM_TimeBaseStructure.TIM_ClockDivision = 0;
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
  TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
  TIM_PrescalerConfig(TIM2, 71, TIM_PSCReloadMode_Immediate);   
  
  pRmtCtrlCodeBuf = RmtCtrlCodeBuf;   /* initiate the buffer pointer */
  output_state = OUTPUT_CARRIER;      /* initiate the output state */
  
  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Timing;   /* Output Compare Timing Mode configuration: Channel1 */
  TIM_OCInitStructure.TIM_Pulse = *pRmtCtrlCodeBuf;      /* set the value to compare */
  TIM_OC1Init(TIM2, &TIM_OCInitStructure);
  TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Disable);    /* disable preload */
  TIM_UpdateDisableConfig(TIM2, ENABLE);                /* disable update event */
    
  TIM2->EGR = 0x01;                   /* initiate the count */ 
  
  TIM2->CR1 |= CR1_CEN_Set;           /* TIM2 enable counter */  

  TIM2->DIER |= TIM_IT_CC1;           /* Enable the CC1 Interrupt Request */
}

/**
  * @brief  configurate the tim3 to capture the Irda signal 
  * @param  None
  * @retval : None
  */

void Irda_In_Capture_Configuration(void)
{
   /* TIM3 configuration: Input Capture mode ------------------------
     The external signal is connected to TIM3 CH3 pin (PB.0), 
     The Falling edge is used as active edge,
     The TIM3 CCR3 is used to compute the frequency value 
  ------------------------------------------------------------ */
  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
  
  TIM_DeInit(TIM3);                        /* deinitiate tim3 */
  
  TIM_TimeBaseStructure.TIM_Period = 65535;       /* Time base configuration CK_INT=72M/(71+1)=1MHz */
  TIM_TimeBaseStructure.TIM_Prescaler = 0;
  TIM_TimeBaseStructure.TIM_ClockDivision = 0;
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
  TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
  TIM_PrescalerConfig(TIM3, 71, TIM_PSCReloadMode_Immediate); 
  
  TIM3->CCMR2 = 0x01/* IC3 ON TI3 */ | 0x20 /* N=4 */;  /*TIM3 CC3 in capture mode,without prescaler */

  TIM3->CCER = 0x0300;                /* channel3 capture enable, falling edge */    

  capture_state = CAPTURE_START;      /* initiate the status  */

  num_capture_codes = 0;              /* initiate the counter */
  
  pRmtCtrlCodeBuf = RmtCtrlCodeBuf;  /* initiate the buffer pointer */
  
  TIM3->CR1 |= CR1_CEN_Set;           /* TIM3 enable counter */  

  TIM3->DIER |= TIM_IT_CC3;           /* Enable the CC3 Interrupt Request */
}

/**
  * @brief  configurate the tim3 to generate the 38KHz carrier
  * @param  None
  * @retval : None
  */
void carrier_38K_configuration(void)
{
  /* -----------------------------------------------------------------------
    TIM3CLK = 72 MHz, Prescaler = 0x0, TIM3 counter clock = 72 MHz
    TIM3 ARR Register = 1893 => TIM3 Frequency = TIM3 counter clock/(ARR + 1)
    TIM3 Frequency = 38 KHz.
    TIM3 Channel4 duty cycle = (TIM3_CCR4/ TIM3_ARR)* 100 = 33.33% 630
  ----------------------------------------------------------------------- */
  
  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
  TIM_OCInitTypeDef  TIM_OCInitStructure;    

  TIM_DeInit(TIM3);                           /* deinitiate tim3 */ 
  
  TIM_TimeBaseStructure.TIM_Period = 1893;    /* Time base configuration CK_INT=72M/(1893+1)=38KHz */
  TIM_TimeBaseStructure.TIM_Prescaler = 0;
  TIM_TimeBaseStructure.TIM_ClockDivision = 0;
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
  TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);

  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;   /* PWM1 Mode configuration: Channel4 33%duty cycle*/
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OCInitStructure.TIM_Pulse = 630;
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;

  TIM_OC4Init(TIM3, &TIM_OCInitStructure);

  TIM_OC4PreloadConfig(TIM3, TIM_OCPreload_Enable);

  TIM_ARRPreloadConfig(TIM3, ENABLE);
  
  TIM3->CR1 |= CR1_CEN_Set;   /* Enable the TIM3(channel4) Counter sending carrier */
}


/**
  * @brief  Configures the TIM4 to generate the interrupt when there is no signal on the Irda line for 5ms
  * @param  None
  * @retval : None
  */
void Timer_Configuration(void)
{
  /* ---------------------------------------------------------------
    TIM3 Configuration: Timing Mode:
    TIM3CLK = 72 MHz, Prescaler = 23, TIM3 counter clock = 3MHz
    TIM3 ARR Register = 59999=> TIM3 Frequency = TIM3 counter clock/(ARR + 1)
    TIM3 Frequency = 50Hz (20ms).
  --------------------------------------------------------------- */
  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
  TIM_OCInitTypeDef  TIM_OCInitStructure;
  
  TIM_DeInit(TIM4);         /* deinitiate */
  
  TIM_TimeBaseStructure.TIM_Period = 14999;   /* Time base configuration */
  TIM_TimeBaseStructure.TIM_Prescaler = 23;
  TIM_TimeBaseStructure.TIM_ClockDivision = 0;
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
  TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);

  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Timing;   /* Timing Mode :Channel1 */
  TIM_OC1Init(TIM4, &TIM_OCInitStructure);
  TIM_OC1PreloadConfig(TIM4, TIM_OCPreload_Enable);
  TIM_ARRPreloadConfig(TIM4, ENABLE);  

  TIM_ITConfig(TIM4, TIM_IT_CC1, ENABLE);   /* TIM IT enable */
}


/**
  * @brief  Configures the nested vectored interrupt controller.
  * @param  None
  * @retval : None
  */
void NVIC_Configuration(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;

  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
  
  NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
  
  NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
  
  NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);  
  
  NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);  
}


/**
  * @brief  Configure the Irda Pins.
  * @param  None
  * @retval : None
  */
void GPIO_Configuration(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
  
  /* Configure PB1 as Irda Out and PB0 as Irda In */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIO_Init(GPIOB, &GPIO_InitStructure);
  
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_Init(GPIOB, &GPIO_InitStructure);  
  
  /* GPIOB configuration: PB12 PB13 PB14 PB15 as led controller */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
  GPIO_Init(GPIOB, &GPIO_InitStructure);  
}

/**
  * @brief  Configure the KEY configuration 
  * @param  None
  * @retval : None
  */
void Key_Configuration(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
  
  /* configure the PB7 as the EXTI lines to handle the KEY*/ 
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIO_Init(GPIOB, &GPIO_InitStructure);  
  
  EXTI_InitTypeDef EXTI_InitStructure;  
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource7);
  EXTI_InitStructure.EXTI_Line = EXTI_Line7;                 
  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
  EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  EXTI_Init(&EXTI_InitStructure);    
}

/**
  * @brief  Configure the user interface 
  * @param  None
  * @retval : None
  */
void user_interface_configuration(void)
{
  GPIO_Configuration();

  Key_Configuration();

  global_state = GLOBAL_IDLE;
  
  global_state_backup = GLOBAL_BACKUP;
}

